package com.swh.ribbon;

import java.net.URI;
import java.util.List;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.netflix.client.ClientFactory;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.config.ConfigurationManager;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import com.netflix.niws.client.http.RestClient;
import com.swh.user.domain.UserEntity;

@SpringBootApplication
//@RibbonClients(defaultConfiguration=MyDefaultRibbonConfig.class)  //设置的配置，就不会去加载默认的配置信息
@RibbonClients
@RestController
@EnableDiscoveryClient
public class UserCloudRibbonApplication {
    
    private static final Logger logger = LoggerFactory.getLogger(UserCloudRibbonApplication.class);
  @Autowired
  private SpringClientFactory clientFactory;
  
  @Autowired
  private LoadBalancerClient loadBalancerClient;
  
  @Bean
  @LoadBalanced
  RestTemplate restTemplate() {
      return new RestTemplate();
  }
//
  @Autowired
  private RestTemplate restTemplate;
  
  @RequestMapping("/getLBServer")
  public UserEntity getLBServer(){
	  //serviceId必须和配置文件中 ribbon.client.name的值一致,表示取客户配置参数
      ServiceInstance serviceInstance = this.loadBalancerClient.choose("myclientDefault");
      System.out.println("===" + ":" + serviceInstance.getServiceId() + ":" + serviceInstance.getHost() + ":" + serviceInstance.getPort()
	      +";URI:"+serviceInstance.getUri());
      UserEntity userEntity = this.restTemplate.getForObject("http://user-cloud-biz-service/userService/getUserInfo/1", UserEntity.class);
      logger.info(">>>>>>>>>返回的结果："+ReflectionToStringBuilder.toString(userEntity));
      return userEntity ;
      
  }
  
  @RequestMapping("/getServer")
  public UserEntity getServer(){
      DynamicServerListLoadBalancer<Server> lb = (DynamicServerListLoadBalancer<Server>) clientFactory.getLoadBalancer("myclient");
//      ZoneAwareLoadBalancer<Server> lb = (ZoneAwareLoadBalancer<Server>) clientFactory.getLoadBalancer("myclient");
      
      ServerList<Server> serverList = lb.getServerListImpl();
      Server server = lb.chooseServer();
      String url = "http://"+server.getHost()+":"+server.getPort()+"/userService/getUserInfo/1" ;
      logger.info(">>>>>>>>>>>>url:"+url);
      RestTemplate restTemplate = new RestTemplate();
      UserEntity userEntity = restTemplate.getForObject(url , UserEntity.class) ;
      logger.info(">>>>>>>>>返回的结果："+ReflectionToStringBuilder.toString(userEntity));
      return userEntity ;
  }

  @RequestMapping("/")
  public String getServerList() throws Exception {
      StringBuilder sb = new StringBuilder();
      ZoneAwareLoadBalancer<Server> lb = (ZoneAwareLoadBalancer<Server>) clientFactory.getLoadBalancer("myclient");
      ServerList<Server> serverList = lb.getServerListImpl();
      
      List<Server> serverDetailList = serverList.getInitialListOfServers();
      if (!CollectionUtils.isEmpty(serverDetailList)) {
          for (Server s : serverDetailList) {
              sb.append(s.getHost() + "," + s.getPort()+" ,"+ReflectionToStringBuilder.toString(s.getMetaInfo()));
              logger.info(">>>>>>>>>>>>>"+s.getHost() + "," + s.getPort()+" ,"+s.getMetaInfo());
              logger.info(">>>>>>>>>>>>>AppName:"+s.getMetaInfo().getAppName() + ",InstanceId:" + s.getMetaInfo().getInstanceId()
        	      +" ,ServerGroup："+s.getMetaInfo().getServerGroup()+",ServiceIdForDiscovery："+s.getMetaInfo().getServiceIdForDiscovery()
        	      +",Class："+s.getMetaInfo().getClass());
//              RestClient client = (RestClient) ClientFactory.getNamedClient("myclient"); // 2
              String url = "http://"+s.getHost()+":"+s.getPort()+"/userService/getUserInfo/1" ;
              logger.info(">>>>>>>>>>>>url"+url);
              RestTemplate restTemplate = new RestTemplate();
              UserEntity userEntity = restTemplate.getForObject(url , UserEntity.class) ;
	     logger.info(">>>>>>>>>返回的结果："+ReflectionToStringBuilder.toString(userEntity));
//              return ReflectionToStringBuilder.toString(userEntity);
          }
      } else {
	  sb.append(">>>>>>>>>>>>>no service");
	  logger.info(">>>>>>>>>>>>>no service");
      }
     DefaultClientConfigImpl clientConfig = (DefaultClientConfigImpl) lb.getClientConfig();
     sb.append("\n >clientConfig:"+ReflectionToStringBuilder.toString(clientConfig)) ;
     logger.info(">>>>>>>>>>>>>>>>clientConfig:"+ReflectionToStringBuilder.toString(clientConfig));
     return sb.toString() ;
  }
  
  /**
   * 测试ribbon load Balancer
   * @throws Exception
   * @author sangwenhao
   * @date 2017年1月9日
   */
  public void testClientRibbon() throws Exception{
      ConfigurationManager.loadPropertiesFromResources("config.properties"); // 1.通过archaius加载配置文件
      System.out.println(ConfigurationManager.getConfigInstance().getProperty("myclient.ribbon.listOfServers"));
      RestClient client = (RestClient) ClientFactory.getNamedClient("myclient"); // 2.通过ClientFactory获取指定名称client，在该方法中就获取了loadBalancer
      HttpRequest request = HttpRequest.newBuilder().uri(new URI("/")).build(); // 3.构建请求
      for (int i = 0; i < 20; i++) {
          HttpResponse response = client.executeWithLoadBalancer(request); // 4.执行loadBalancer,会发现调用的服务会在listOfServers列表中的数据切换
          System.out.println("Status code for " + response.getRequestedURI() + "  :" + response.getStatus());
      }
      ZoneAwareLoadBalancer lb = (ZoneAwareLoadBalancer) client.getLoadBalancer();
      System.out.println(lb.getLoadBalancerStats());
      ConfigurationManager.getConfigInstance().setProperty("myclient.ribbon.listOfServers",
              "www.qq.com:80,www.u51.xin"); // 5.修改可用服务列表
      System.out.println("changing servers ...");
      Thread.sleep(3000); 
      for (int i = 0; i < 20; i++) {
          HttpResponse response = client.executeWithLoadBalancer(request);
          System.out.println("Status code for " + response.getRequestedURI() + "  : " + response.getStatus());
      }
      System.out.println(lb.getLoadBalancerStats()); // 6.获取loadBalancer状态

  }
  /*
  public DiscoveryEnabledServer chooseServer(){
      IRule rule = new AvailabilityFilteringRule();
      ServerList<DiscoveryEnabledServer> list = new DiscoveryEnabledNIWSServerList("MyVIP:7001");
      ServerListFilter<DiscoveryEnabledServer> filter = new ZoneAffinityServerListFilter<DiscoveryEnabledServer>();
      ZoneAwareLoadBalancer<DiscoveryEnabledServer> lb = LoadBalancerBuilder.<DiscoveryEnabledServer>newBuilder()
              .withDynamicServerList(list)
              .withRule(rule)
              .withServerListFilter(filter)
              .buildDynamicServerListLoadBalancer();   
      DiscoveryEnabledServer server = lb.chooseServer();  
      return server ;
  }
  */

  public static void main(String[] args) {
      SpringApplication app = new SpringApplicationBuilder(UserCloudRibbonApplication.class).build();
      app.run(args);
}
}
